/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

 /***************************************************************************
 * Name: file_accessor_impl.cpp
 *
 * Purpose: file accessor(persistency) inner implementation for base library
 *
 * Developer:
 *   wen.gu , 2019-10-15
 *
 * TODO:
 *
 ***************************************************************************/

 /******************************************************************************
 **    INCLUDES
 ******************************************************************************/
#include "panda/per/internal/file_accessor_impl.h"

#include <stdlib.h>
#include <fcntl.h> 
#include <io.h> 

#define LOG_TAG "faci"
#include "panda/core/log.h"

namespace panda
{
namespace per
{
namespace internal_impl
{
/******************************************************************************
 **    MACROS
 ******************************************************************************/

/******************************************************************************
 **    VARIABLE DEFINITIONS
 ******************************************************************************/



/******************************************************************************
 **    FUNCTION DEFINITIONS
 ******************************************************************************/

FileAccessorImpl::FileAccessorImpl()
{
    /** todo something */
}

FileAccessorImpl::~FileAccessorImpl()
{
    /** todo something */
}

/** readOnly: true: read only, false: read/write mode */
bool FileAccessorImpl::openFile(const std::string& fileName, bool readOnly)
{
    PandaErrc ret;

    if (readOnly)
    {
        ret = mFs.fileOpen(fileName, panda::core::VFS::OpenMode::R);
    }
    else
    {
        ret = mFs.fileOpen(fileName.c_str(), panda::core::VFS::OpenMode::RW);
    }

    if (bool(ret))
    {
        mReadOnly = readOnly;
        return true;
    }
    else
    {
        LOGE("open file(%s) failed(%s)\n", fileName.c_str(), strerror(errno));
    }

    return false;
}

/**@brief Returns the current position in bytes in the file from start*/
pos_type FileAccessorImpl::tell()
{
    return mPos;
}

/**@brief Sets the position in bytes in the file from beginning */
FileAccessor::PandaErrc FileAccessorImpl::seek(pos_type const pos)
{
    return seek(pos, SeekDirection::kBeg);
}

/**@brief  sets the position in bytes in the file in relation to the SeekDirection */
FileAccessor::PandaErrc FileAccessorImpl::seek(off_type const off, SeekDirection const dir)
{
    int64_t curPos = mPos;
    int64_t totalSize = mFs.fileSize();
    int64_t targetPos;

    switch (dir)
    {
    case SeekDirection::kBeg: targetPos = off; break;
    case SeekDirection::kCur: targetPos = curPos + off; break;
    case SeekDirection::kEnd: targetPos = totalSize - off; break;
    default:
        return PandaErrc::UnsupportedType;
        break;
    }

    if ((0 <= targetPos) && (targetPos <= totalSize))
    {

        mPos = targetPos;
        return PandaErrc::OK;
    }

    return PandaErrc::OutOfRange;
}

pos_type FileAccessorImpl::size()
{
    return mFs.fileSize();
}

/** for read */
/**@breif reads n bytes into char pointer and returns actual number
*        that were read, if < 0, error occurs.
*        
*/

int_type FileAccessorImpl::read(char* const s, std::size_t const n)
{

    int32_t ret = mFs.fileRead(mPos, s, n);

    if (ret == n)
    {
        mPos += n;
        return ret;
    }

    return -1;
}


/** for write */
/**@breif the function flushes and force the OS to write its data to persistent storage */
void FileAccessorImpl::fsync()
{
    mFs.fileSync();
}

/** writes n bytes from s and returns actual number of written bytes 
    *  if < 0, error occurs.
    */
int_type FileAccessorImpl::write(char const* const s, std::size_t const n)
{
    if (!mReadOnly)
    {
        int32_t ret = mFs.fileWrite(mPos, s, n);

        if (ret == n)
        {
            mPos += n;
            return ret;
        }
    } 

    return -1;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

} /** namespace internal_impl */
} /** namespace per */
} /** namespace panda */
